﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Pex.Framework;
using Microsoft.SharePoint.Behaviors;
using Microsoft.SharePoint.Administration.Behaviors;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Moles;

namespace Shweet.Repository.Tests
{
    [PexClass(typeof(Teams))]
    [TestClass]
    public partial class TeamsTests
    {
        [TestMethod]
        [HostType("Moles")]
        public void Discover_OneSiteCollectionTwoWebsWithShweetLists_ReturnTwo()
        {
            //Arrange
            BSPSecurity.SetIdentity();
            BSPContext context = BSPContext.SetCurrent();
            BSPSite site = context.SetSite();
            site.SetWebApplication();  //?? could this be done by default

            BSPWeb rootweb = site.SetRootWeb();
            SetUpWeb(rootweb, "a", "http://a", true);
            rootweb.Webs.SetNext(MakeWeb("b", "http://b/", true));   

            //Act
            Teams teamRepository = new Teams();
            List<Team> teams = teamRepository.Discover();

            //Assert
            Assert.AreEqual(2, teams.Count);
            Assert.AreEqual("a", teams[0].Name);
            Assert.AreEqual("b", teams[1].Name);
            Assert.AreEqual("http://a/", teams[0].Url);
            Assert.AreEqual("http://b/", teams[1].Url);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Discover_TwoSiteCollectionsOneWebWithShweets_ReturnsTwoTeams()
        {
            //Arrange
            BSPSecurity.SetIdentity();
            BSPContext context = BSPContext.SetCurrent();
            BSPSite site = context.SetSite();
            BSPWebApplication webApp = site.SetWebApplication();

            BSPSite siteTwo = new BSPSite();
            webApp.Sites.SetNext(siteTwo);

            BSPWeb rootweb1 =  site.SetRootWeb();
            SetUpWeb(rootweb1, "sc1", "http://sc1", true);

            BSPWeb rootweb2 = siteTwo.SetRootWeb();
            SetUpWeb(rootweb2, "sc2", "http://sc2", true);

            //Act
            Repository.Teams teamRepository = new Repository.Teams();
            List<Team> teams = teamRepository.Discover();

            //Assert
            Assert.AreEqual(2, teams.Count);
            Assert.AreEqual("sc1", teams[0].Name);
            Assert.AreEqual("sc2", teams[1].Name);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Discover_OneSiteCollectionTwoNestedWebsWithShweetListOnLastWeb_ReturnOne()
        {
            //Arrange
            BSPSecurity.SetIdentity();
            BSPContext context = BSPContext.SetCurrent();
            BSPSite site = context.SetSite();
            site.SetWebApplication();

            BSPWeb rootweb = site.SetRootWeb();
            SetUpWeb(rootweb, "a", "http://a", false);
            rootweb.Webs.SetNext(MakeWeb("b", "http://b", true)); 

            //Act
            Teams teamRepository = new Teams();
            List<Team> teams = teamRepository.Discover();

            //Assert
            Assert.AreEqual(1, teams.Count);
            Assert.AreEqual("b", teams[0].Name);
            Assert.AreEqual("http://b/", teams[0].Url);
        }


        //TODO = change to use Uri as this is needed internally - but Pex fail to gen tests
        //       is this still valid for Pex and whats the best way to get it to assume the type?
        [PexMethod]
        public void Discover_OneSiteCollectionWithARootWebWithShweetList_OneTeamReturned(string listname, string webTitle,
                                                                                     Uri webUrl)
        {
            PexAssume.IsNotNull(webTitle);
            PexAssume.IsNotNull(webUrl);
            //State
            BSPSecurity.SetIdentity();

            BSPContext context = BSPContext.SetCurrent();
            BSPSite site = context.SetSite();
            site.SetWebApplication();

            BSPWeb rootWeb = site.SetRootWeb();
            rootWeb.Title = webTitle;
            rootWeb.Url = webUrl.AbsoluteUri;
            BSPList shweetList = rootWeb.Lists.SetOne();
            shweetList.Title = listname;

            // Act
            ITeams shweetTeams = new Teams();
            List<Team> teams = shweetTeams.Discover();

            // Assert
            Assert.AreEqual(listname == "Shweets" ? 1 : 0, teams.Count);
            // Any way to pex the state?
            PexAssert.ImpliesIsTrue(teams.Count == 1, () => rootWeb.Title == teams[0].Name);
            PexAssert.ImpliesIsTrue(teams.Count == 1, () => rootWeb.Url == teams[0].Url);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Add_OneTeam_AddsTeam()
        {
            //Act
            List<Team> teamToAdd = new List<Team>() { new Team() { Name = "a", Url = "http://a" } };

            BSPContext context = BSPContext.SetCurrent();
            BSPWeb web = context.SetWeb();
            BSPList list = web.Lists.SetOne();
            list.Fields.SetAll("Title", "Url");
            list.Title = "ShweetTeams";
            list.Items.SetEmpty();

            //Example of manually adding moles where the functionality does not yet exisit in the Behaviours
            new MSPList(list)
            {
                AddItem = () =>
                    {
                        var item = list.Items.SetNext();
                        new MSPListItem(item) { TitleGet = () => (string)item.Values[0] };
                        item.Values.Count = 2; //2 fields Title & Url
                        return item;
                    },
            };


            //Act
            ITeams shweetTeams = new Teams();
            shweetTeams.Add(teamToAdd);

            //Assert
            Assert.AreEqual(1, list.Items.Count);
            Assert.AreEqual("a", list.Items[0].Title);
            var urlValue = list.Items[0]["Url"] as SPFieldUrlValue;
            Assert.IsNotNull(urlValue);
            Assert.AreEqual("http://a", urlValue.Url);
            Assert.AreEqual("a", urlValue.Description);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Remove_OneTeamNoExistingTeams_NoAction()
        {
            //Act
            List<Team> teamToRemove = new List<Team>() { new Team() { Name = "a", Url = "http://a" } };

            BSPContext context = BSPContext.SetCurrent();
            BSPWeb web = context.SetWeb();
            BSPList list = web.Lists.SetOne();
            list.Title = "ShweetTeams";
            list.Items.SetEmpty();
            list.Fields.SetAll("Title", "Url");

            //Act
            ITeams shweetTeams = new Teams();
            shweetTeams.Remove(teamToRemove);

            //Assert
            Assert.AreEqual(0, list.Items.Count);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Remove_OneTeamExistingTeamExists_RemoveTeam()
        {
            //Act
            List<Team> teamToRemove = new List<Team>() { new Team() { Name = "a", Url = "http://a" } };

            BSPContext context = BSPContext.SetCurrent();
            BSPWeb web = context.SetWeb();
            BSPList list = web.Lists.SetOne();
            list.Title = "ShweetTeams";
            list.Items.SetEmpty();
            list.Fields.SetAll("Title", "Url");

            new MSPListItemCollection(list.Items)
            {
                DeleteItemByIdInt32 = (id) =>
                    {
                        list.Items.SetEmpty(); 
                    }
            };

            BSPListItem item = list.Items.SetOne();
            item.Values.SetAll("a", "http://a");

            new MSPListItem(item)
            {
                IDGet = () => 1,
                TitleGet = () => "a"
            };

            //Act
            ITeams shweetTeams = new Teams();
            shweetTeams.Remove(teamToRemove);

            //Assert
            Assert.AreEqual(0, list.Items.Count);
        }

        [TestMethod]
        [HostType("Moles")]
        public void Remove_OneTeamNotOnfollowList_LeaveTeam()
        {
            //Act
            List<Team> teamToRemove = new List<Team>() { new Team() { Name = "a", Url = "http://a" } };

            BSPContext context = BSPContext.SetCurrent();
            BSPWeb web = context.SetWeb();
            BSPList list = web.Lists.SetOne();
            list.Title = "ShweetTeams";
            list.Items.SetEmpty();
            list.Fields.SetAll("Title", "Url");

            BSPListItem item = list.Items.SetOne();
            item.Values.SetAll("b", "http://b");

            //Manuall add mole where missing from the behaviour
            new MSPListItem(item)
            {
                TitleGet = () => "b"
            };

            //Act
            ITeams shweetTeams = new Teams();
            shweetTeams.Remove(teamToRemove);

            //Assert
            Assert.AreEqual(1, list.Items.Count);
        }

        private static BSPWeb MakeWeb(string title, string url, bool hasShweetList)
        {
            var web = new BSPWeb();
            return SetUpWeb(web, title, url, hasShweetList);
        }

        private static BSPWeb SetUpWeb(BSPWeb web, string title, string url, bool hasShweetList)
        {
            web.Title = title;
            web.Url = url;
            web.Webs.SetEmpty();
            web.Lists.SetEmpty();
            if (hasShweetList)
            {
                BSPList listOne = web.Lists.SetOne();
                listOne.Title = "Shweets";
            }
            return web;
        }

    }
}
